﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using Sherwood.Security;

namespace Sherwood.Content.Contracts
{
    public partial class updateRecordsRequest
    {
        /// <summary>
        /// Writes the content to a memory stream that is suitable to use with a WCF method taking stream as parameter.
        /// </summary>
        public MemoryStream GetAsMemoryStream()
        {
            var requestStream = new MemoryStream();
            using (var writer = XmlWriter.Create(requestStream, new XmlWriterSettings
                                                                    {
                                                                        OmitXmlDeclaration = true,
                                                                        Indent = false,
                                                            NamespaceHandling = NamespaceHandling.OmitDuplicates
                                                                    }))
            {
                Save(writer);
            }
            requestStream.Seek(0, SeekOrigin.Begin);
            return requestStream;
        }

        /// <summary>
        /// Signs the content of <see cref="content"/> and stores the signature in <see cref="Contracts.client.signature"/>.
        /// Use <see cref="VerifySignature"/> to verify the signature.
        /// </summary>
        /// <param name="privateKey">The private key used to sign the message</param>
        public void Sign(string privateKey)
        {
            if (string.IsNullOrEmpty(privateKey)) throw new ArgumentNullException("privateKey");
            var rsa = Rsa.FromPrivateKey(privateKey);
            var message = GetSignableMessage();
            if(client == null) client = new client();
            client.signature = rsa.SHA1Sign(message);
        }

        /// <summary>
        /// Verifies that the signature in <see cref="Contracts.client.signature"/> matches the content of <see cref="content"/>.
        /// </summary>
        /// <param name="publicKey">The public key of the signing party</param>
        /// <returns>True if signature is valid, else false</returns>
        public bool VerifySignature(string publicKey)
        {
            if (string.IsNullOrEmpty(publicKey)) throw new ArgumentNullException("publicKey");
            if (client == null || string.IsNullOrEmpty(client.signature)) throw new InvalidOperationException("signature is empty");
            
            var rsa = Rsa.FromPublicKey(publicKey);
            var message = GetSignableMessage();
            return rsa.SHA1Verify(message, client.signature);
        }

        private string GetSignableMessage()
        {
            if(content == null)
                throw new InvalidOperationException("content is empty");

            var sb = new StringBuilder();
            using (var xmlWriter = XmlWriter.Create(sb,
                                                    new XmlWriterSettings
                                                        {
                                                            Indent = false,
                                                            OmitXmlDeclaration = true,
                                                            ConformanceLevel = ConformanceLevel.Fragment,
                                                            NamespaceHandling = NamespaceHandling.OmitDuplicates
                                                        }))
            {
                content.Untyped.WriteTo(xmlWriter);
            }
            sb.Replace(" xmlns=\"Sherwood.Content.Contracts\"", string.Empty);
            return sb.ToString();
        }
    }
}
